package net.lovesrc.allin.biz.treex;

import com.alibaba.fastjson.JSONObject;
import com.zhouzhou.fastjava.BizException;
import com.zhouzhou.fastjava.http.FilePart;
import com.zhouzhou.fastjava.http.MyHttpRequest;
import com.zhouzhou.fastjava.http.Requests;
import com.zhouzhou.fastjava.util.FileKit;
import net.lovesrc.allin.biz.idcard.IdCardService;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.BasicCookieStore;

import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.Date;
import java.util.regex.Pattern;

@Service
public class TreexRegisterService extends BaseTreexService {

    private JSONObject getFreeIdCard() {
        String sql = "select * from t_id_card where worked = 1 and frontOcrStatus = 'normal' and backOcrStatus = 'normal' " +
                " and idCardNumber not in (select idCardNumber from t_treex_account where idCardNumber is not null) " +
                " and idCardNumber not in (select idCardNumber from t_treex_used_id) " +
                " limit 1";
        JSONObject row = queryForRow(jdbcTemplate, sql);
        if (row == null) {
            throw BizException.messageOf("无可用的身份证信息了");
        }
        return row;
    }


    private String doGetNewMobile() {
        for (; ; ) {
            String mobile = getMobileVerifyCodeWrapper().getPhone();
            if (jdbcTemplate.queryForObject("select count(1) from t_treex_account where mobile = ?", long.class, mobile) > 0) {
                getMobileVerifyCodeWrapper().addBlack(mobile);
                continue;
            }
            return mobile;
        }
    }

    public String newRegister(String inviteCode) {

        if (StringUtils.isBlank(inviteCode)) {
            throw BizException.messageOf("邀请码不能为空");
        }
        if (jdbcTemplate.queryForObject("select count(1) from t_treex_account where inviteCode = ?", int.class, inviteCode) == 0) {
            throw BizException.messageOf("{} 在系统中不存在", inviteCode);
        }

        String mobile = doGetNewMobile();
        boolean sendRegCodeSuccess = false;
        CookieStore cookieStore = new BasicCookieStore();
        HttpClient httpClient = newHttpClientWithMyProxy(null, cookieStore);
        MyHttpRequest.get(httpClient, "https://www.gdpro.pro/user/register")
                .executeUtilReturn200();
        MyHttpRequest.get(httpClient, "https://www.gdpro.pro/api/v1/session?" + System.currentTimeMillis())
                .executeUtilReturn200();
        for (int i = 0; i < 5; i++) {
            String imageVerifyCode;
            try {
                byte[] imageVerifyBytes = MyHttpRequest.get(httpClient, "https://www.gdpro.pro/api/v1/servlet/ImageCode?" + System.currentTimeMillis())
                        .executeUtilReturn200()
                        .asBytes();
                ByteArrayInputStream imageVerifyIs = new ByteArrayInputStream(imageVerifyBytes);
                imageVerifyCode = daMaService.recognise("1004", "image/jpeg", imageVerifyIs);
            } catch (Exception e) {
                logger.error("get image verify code error", e);
                continue;
            }
            JSONObject resJson;
            try {
                resJson = MyHttpRequest.post(httpClient, "https://www.gdpro.pro/api/v1/sendRegCode")
                        .param("code", imageVerifyCode)
                        .param("name", mobile)
                        .executeUtilReturn200()
                        .asJson();
            } catch (Exception e) {
                logger.error("send reg code error", e);
                continue;
            }
            int code = resJson.getIntValue("code");
            //3 验证码不正确
            //4 已被注册
            if (code == 200) {
                sendRegCodeSuccess = true;
                break;
            } else if (code == 4) {
                getMobileVerifyCodeWrapper().releasePhone(mobile);
                throw BizException.messageOf("{} 已被注册", mobile);
            } else {
                continue;
            }
        }
        if (!sendRegCodeSuccess) {
            getMobileVerifyCodeWrapper().releasePhone(mobile);
            throw BizException.messageOf("短信验证码发送失败");
        }
        String verifyCode = getMobileVerifyCodeWrapper().getVerifyCodeFromPhone(mobile);
        String password = randomAlphanumeric(8, 14);
        JSONObject regResJson = MyHttpRequest.post(httpClient, "https://www.gdpro.pro/api/v1/register")
                .param("name", mobile)
                .param("pwd", password)
                .param("code", verifyCode)
                .param("inviteCode", inviteCode)
                .executeUtilReturn200()
                .asJson();
        JSONObject newRow = new JSONObject()
                .fluentPut("mobile", mobile)
                .fluentPut("verifyCode", verifyCode)
                .fluentPut("byInviteCode", inviteCode)
                .fluentPut("password", password)
                .fluentPut("registerResText", regResJson.toJSONString())
                .fluentPut("registerCode", regResJson.getIntValue("code"))
                .fluentPut("cookies", Requests.toCookieString(cookieStore));
        insertRow(jdbcTemplate, "t_treex_account", newRow);
        if (isOkResJson(regResJson)) {
            safeRun(() -> {
                JSONObject row = queryForRow(jdbcTemplate, "select * from t_treex_account where mobile = ?", mobile);
                this.ensureLogin(row);
            });
        }
        return mobile;
    }

    /**
     * 确保有字母和数字
     */
    private String randomAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) {
        for (; ; ) {
            String chars = RandomStringUtils.randomAlphanumeric(minLengthInclusive, maxLengthExclusive);
            if (Pattern.compile("\\d+").matcher(chars).find()
                    && Pattern.compile("[a-zA-Z]+").matcher(chars).find()
            ) {
                return chars;
            }
        }
    }

    public void authId(String mobile) {
        jdbcTemplate.update("update t_treex_account set idNextSyncTime = ? where mobile = ?", DateUtils.addMinutes(new Date(), 5), mobile);
        try {
            this.doAuthId(mobile);
        } catch (Exception e) {
            logger.error("auth id error, {}", mobile, e);
            jdbcTemplate.update("update t_treex_account set idStatus = 'failure', idTime = ?, idErrorMsg = ? where mobile = ?", new Date(), ExceptionUtils.getMessage(e), mobile);
        }
    }

    private synchronized void doAuthId(String mobile) {
        // 登录
        JSONObject row = queryForRow(jdbcTemplate, "select * from t_treex_account where mobile = ?", mobile);
        String idStatus = row.getString("idStatus");
        if ("success".equals(idStatus)) {
            return;
        }

        UserSessionMeta userSessionMeta = ensureLogin(row);
        JSONObject userJson = userSessionMeta.getUserJson();
        if (checkIdStatus(mobile, userJson)) {
            return;
        }
        if (userJson.getBooleanValue("authDeepPost")) {
            return;
        }

        if ("adv-submitted".equalsIgnoreCase(idStatus)) {
            JSONObject sets = new JSONObject()
                    .fluentPut("idStatus", "adv-submitted-failure")
                    .fluentPut("idTime", new Date())
                    .fluentPut("idErrorMsg", "提交过，但失败了");
            updateRow(jdbcTemplate, "t_treex_account", sets, "mobile = ?", mobile);
            return;
        }

        HttpClient httpClient = userSessionMeta.getHttpClient();
        if (userJson.getBooleanValue("auth")) {
            String realName = row.getString("realName");
            String idCardNumber = row.getString("idCardNumber");
            File dir = new File(IdCardService.ROOT, idCardNumber);
            File file1 = FileKit.tryGetFile(dir, "1", IdCardService.ACCEPT_EXTENSIONS);
            File file2 = FileKit.tryGetFile(dir, "2", IdCardService.ACCEPT_EXTENSIONS);
            File file3 = FileKit.tryGetFile(dir, "3", IdCardService.ACCEPT_EXTENSIONS);

            // 做高级认证
            String fIdentityPath1 = uploadFile(httpClient, realName + "_正面." + FilenameUtils.getExtension(file1.getName()), "1", file1);
            String fIdentityPath2 = uploadFile(httpClient, realName + "_反面." + FilenameUtils.getExtension(file2.getName()), "2", file2);
            String fIdentityPath3 = uploadFile(httpClient, realName + "_手持." + FilenameUtils.getExtension(file3.getName()), "3", file3);

            JSONObject resJson = MyHttpRequest.post(httpClient, "https://www.gdpro.pro/api/v1/account/uploadAuth")
                    .param("fIdentityPath1", fIdentityPath1)
                    .param("fIdentityPath2", fIdentityPath2)
                    .param("fIdentityPath3", fIdentityPath3)
                    .executeUtilReturn200()
                    .asJson();
            if (isOkResJson(resJson)) {
                JSONObject sets = new JSONObject()
                        .fluentPut("idStatus", "adv-submitted")
                        .fluentPut("idTime", new Date())
                        .fluentPut("idResText", resJson.toJSONString())
                        .fluentPut("idResCode", resJson.getIntValue("code"))
                        .fluentPut("idErrorMsg", resJson.getString("msg"));
                updateRow(jdbcTemplate, "t_treex_account", sets, "mobile = ?", mobile);
            } else {
                JSONObject sets = new JSONObject()
                        .fluentPut("idStatus", "adv-submitted-failure")
                        .fluentPut("idTime", new Date())
                        .fluentPut("idResText", resJson.toJSONString())
                        .fluentPut("idResCode", resJson.getIntValue("code"))
                        .fluentPut("idErrorMsg", resJson.getString("msg"));
                updateRow(jdbcTemplate, "t_treex_account", sets, "mobile = ?", mobile);
            }
        } else {
            // 实名
            JSONObject idRow = getFreeIdCard();
            String realName = idRow.getString("realName");
            String idCardNumber = idRow.getString("idCardNumber");
            // 做初级认证
            JSONObject resJson = MyHttpRequest.post(httpClient, "https://www.gdpro.pro/api/v1/account/auth")
                    .param("name", realName)
                    .param("no", idCardNumber)
                    .executeUtilReturn200()
                    .asJson();
            JSONObject sets = new JSONObject()
                    .fluentPut("idCardNumber", idCardNumber)
                    .fluentPut("realName", realName)
                    .fluentPut("idStatus", "basic-submitted")
                    .fluentPut("idTime", new Date())
                    .fluentPut("idResText", resJson.toJSONString())
                    .fluentPut("idResCode", resJson.getIntValue("code"))
                    .fluentPut("idErrorMsg", resJson.getString("msg"));
            updateRow(jdbcTemplate, "t_treex_account", sets, "mobile = ?", mobile);

            JSONObject newRow = new JSONObject()
                    .fluentPut("mobile", mobile)
                    .fluentPut("idCardNumber", idCardNumber)
                    .fluentPut("idErrorMsg", resJson.toJSONString());
            insertRow(jdbcTemplate, "t_treex_used_id", newRow);
        }
    }

    private String uploadFile(HttpClient httpClient, String filename, String type, File file) {
        FilePart filePart = FilePart.builder()
                .filename(filename)
                .file(file)
                .contentType(FileKit.getConentType(file.getName()))
                .name("img")
                .build();
        JSONObject uploadJson = MyHttpRequest.post(httpClient, "https://www.gdpro.pro/api/v1/account/upload.html")
                .param("type", type)
                .part(filePart)
                .executeUtilReturn200()
                .asJson();
        checkResJson(uploadJson);
        return uploadJson.getString("data");
    }

    private void onAuthIdSuccess(String mobile, JSONObject row) {

    }

    public void once() {
        JSONObject row = queryForRow(jdbcTemplate, "select * from t_treex_account where mobile = ?", "13624589241");
        ensureLogin(row);
    }

}
